package com.weilele.mvvm.utils.net

import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName
import com.weilele.mvvm.app
import com.weilele.mvvm.gson
import com.weilele.mvvm.okHttpClient
import com.weilele.mvvm.utils.file.spGet
import com.weilele.mvvm.utils.file.spSet
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.BufferedReader
import java.io.IOException
import java.net.URL
import java.util.*

/**
 * cookie存储
 */
@Keep
open class SimpleCookieJar : CookieJar {
    @Keep
    class CookieStoreBean {
        @SerializedName("cookies")
        var cookies: List<Cookie>? = null

        @SerializedName("url")
        var url: String? = null
    }

    private val cookieStoreMap = mutableMapOf<String?, CookieStoreBean>()

    override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
        val host = url.host
        val bean = CookieStoreBean().apply {
            this.url = url.host
            this.cookies = cookies
        }
        cookieStoreMap[host] = bean
        app.spSet(host, gson.toJson(bean))
    }

    override fun loadForRequest(url: HttpUrl): List<Cookie> {
        val host = url.host
        var cookieStoreBean = cookieStoreMap[host]
        if (cookieStoreBean == null) {
            app.spGet(host, "").let {
                if (it.isNotBlank()) {
                    val bean = gson.fromJson(it, CookieStoreBean::class.java)
                    cookieStoreMap[host] = bean
                    cookieStoreBean = bean
                }
            }
        }
        return cookieStoreBean?.cookies ?: ArrayList()
    }
}

/**
 *原始请求
 */
fun <T> Request.yzsHttp(cls: Class<T>, success: (T) -> Unit, fail: (Throwable) -> Unit): Call {
    return okHttpClient.newCall(this).apply {
        enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                fail.invoke(e)
            }

            override fun onResponse(call: Call, response: Response) {
                try {
                    val bodyStr = response.body?.string()
                    if (bodyStr.isNullOrBlank()) {
                        fail.invoke(Exception(response.message))
                    } else {
                        success.invoke(gson.fromJson(bodyStr, cls))
                    }
                } catch (e: Throwable) {
                    e.printStackTrace()
                    fail.invoke(e)
                }
            }
        })
    }
}

/**
 *原始请求
 */
fun Request.yzsHttp(callback: Callback): Call {
    return okHttpClient.newCall(this).apply {
        enqueue(callback)
    }
}

fun Request.yzsHttp(): Response {
    return okHttpClient.newCall(this).execute()
}

/**
 * 原始请求
 */
fun Request.yzsHttp(success: (Response) -> Unit, fail: (Throwable) -> Unit): Call {
    return okHttpClient.newCall(this).apply {
        enqueue(object : Callback {
            override fun onFailure(p0: Call, p1: IOException) {
                fail.invoke(p1)
            }

            override fun onResponse(p0: Call, p1: Response) {
                success.invoke(p1)
            }
        })
    }
}

/**
 * 带http转换的原始请求
 */
fun <T> String.yzsHttpGet(cls: Class<T>, success: (T) -> Unit, fail: (Throwable) -> Unit): Call {
    return Request.Builder()
        .url(this)
        .build().yzsHttp(cls, success, fail)
}

/**
 * 带http转换的原始请求
 */
fun String.yzsHttpGet(callback: Callback): Call {
    return Request.Builder()
        .url(this)
        .build().yzsHttp(callback)
}

fun String.yzsHttpGet(): Response {
    return Request.Builder()
        .url(this)
        .build().yzsHttp()
}

/**
 * 原生的get请求
 */
fun String.yzsHttpGet(success: (Response) -> Unit, fail: (Throwable) -> Unit): Call {
    return Request.Builder()
        .url(this)
        .build().yzsHttp(success, fail)
}

/**
 * 带http转换的原始请求
 */
fun <T> HttpUrl.yzsHttpGet(cls: Class<T>, success: (T) -> Unit, fail: (Throwable) -> Unit): Call {
    return Request.Builder()
        .url(this)
        .build().yzsHttp(cls, success, fail)
}

/**
 * 原生的get请求
 */
fun HttpUrl.yzsHttpGet(success: (Response) -> Unit, fail: (Throwable) -> Unit): Call {
    return Request.Builder()
        .url(this)
        .build().yzsHttp(success, fail)
}

/**
 * 带http转换的原始请求
 */
fun <T> URL.yzsHttpGet(cls: Class<T>, success: (T) -> Unit, fail: (Throwable) -> Unit): Call {
    return Request.Builder()
        .url(this)
        .build().yzsHttp(cls, success, fail)
}

/**
 * 原生的get请求
 */
fun URL.yzsHttpGet(success: (Response) -> Unit, fail: (Throwable) -> Unit): Call {
    return Request.Builder()
        .url(this)
        .build().yzsHttp(success, fail)
}

fun String.yzsHttpPost(
    requestBody: RequestBody,
    success: (Response) -> Unit,
    fail: (Throwable) -> Unit
): Call {
    return Request.Builder()
        .url(this)
        .post(requestBody)
        .build()
        .yzsHttp(success, fail)
}

fun String.yzsHttpPost(
    requestBody: RequestBody,
    callback: Callback
): Call {
    return Request.Builder()
        .url(this)
        .post(requestBody)
        .build()
        .yzsHttp(callback)
}


fun <T> String.yzsHttpPost(
    requestBody: RequestBody,
    cls: Class<T>,
    success: (T) -> Unit,
    fail: (Throwable) -> Unit
): Call {
    return Request.Builder()
        .url(this)
        .post(requestBody)
        .build()
        .yzsHttp(cls, success, fail)
}

fun HttpUrl.yzsHttpPost(
    requestBody: RequestBody,
    success: (Response) -> Unit,
    fail: (Throwable) -> Unit
): Call {
    return Request.Builder()
        .url(this)
        .post(requestBody)
        .build()
        .yzsHttp(success, fail)
}

fun <T> HttpUrl.yzsHttpPost(
    requestBody: RequestBody,
    cls: Class<T>,
    success: (T) -> Unit,
    fail: (Throwable) -> Unit
): Call {
    return Request.Builder()
        .url(this)
        .post(requestBody)
        .build()
        .yzsHttp(cls, success, fail)
}

fun URL.yzsHttpPost(
    requestBody: RequestBody,
    success: (Response) -> Unit,
    fail: (Throwable) -> Unit
): Call {
    return Request.Builder()
        .url(this)
        .post(requestBody)
        .build()
        .yzsHttp(success, fail)

}

fun <T> URL.yzsHttpPost(
    requestBody: RequestBody,
    cls: Class<T>,
    success: (T) -> Unit,
    fail: (Throwable) -> Unit
): Call {
    return Request.Builder()
        .url(this)
        .post(requestBody)
        .build()
        .yzsHttp(cls, success, fail)
}


fun String.yzsHttpPost(
    formData: HashMap<String, String>,
    success: (Response) -> Unit,
    fail: (Throwable) -> Unit
): Call {
    return yzsHttpPost(formData.createFormBody(), success, fail)
}

fun String.yzsHttpPost(
    formData: HashMap<String, String>,
    callback: Callback
): Call {
    return yzsHttpPost(formData.createFormBody(), callback)
}

fun <T> String.yzsHttpPost(
    formData: HashMap<String, String>,
    cls: Class<T>,
    success: (T) -> Unit,
    fail: (Throwable) -> Unit
): Call {
    return yzsHttpPost(formData.createFormBody(), cls, success, fail)
}

fun String.yzsHttpPost(json: String, success: (Response) -> Unit, fail: (Throwable) -> Unit): Call {
    return yzsHttpPost(json.createJsonBody(), success, fail)
}

fun <T> String.yzsHttpPost(
    json: String,
    cls: Class<T>,
    success: (T) -> Unit,
    fail: (Throwable) -> Unit
): Call {
    return yzsHttpPost(json.createJsonBody(), cls, success, fail)

}

fun HashMap<String, String>.createFormBody(): RequestBody {
    val formBody = FormBody.Builder()
    for ((key, value) in this) {
        formBody.add(key, value)
    }
    formBody.build()
    return formBody.build()
}

fun MutableMap<String, String>.createFormBody(): RequestBody {
    val formBody = FormBody.Builder()
    for ((key, value) in this) {
        formBody.add(key, value)
    }
    formBody.build()
    return formBody.build()
}

fun Any.createJsonBody(): RequestBody {
    val json = when (this) {
        is String -> {
            this
        }
        else -> {
            gson.toJson(this)
        }
    }
    return json.toRequestBody("application/json".toMediaTypeOrNull())
}

fun ResponseBody?.getStringBody(): String? {
    this ?: return null
    val bufferedReader = BufferedReader(this.charStream())
    return bufferedReader.readText()
}

fun Response?.getStringBody(): String? {
    return this?.body?.getStringBody()
}